package com.jc.order.controller;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jc.order.constant.ErrorCode;
import com.jc.order.constant.OrderConst;
import com.jc.order.dto.JcPolicyDTO;
import com.jc.order.dto.SystemTenantDTO;
import com.jc.order.service.*;
import com.jc.util.Result;
import com.jc.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 物流险
 */
@Slf4j
public abstract class BaseOrderController {


    @Autowired
    private CargoFeeCalculateService cargoFeeCalculateService;

    @Autowired
    private ApiBaseService apiBaseService;


    @Autowired
    private InsuranceTraditionalService insuranceTraditionalService;

    @Autowired
    private InsuranceCrossService insuranceCrossService;

    protected ObjectMapper objectMapper = new ObjectMapper();


    protected abstract CargoCrossBorderService<JcPolicyDTO> getInsuranceService();

    protected abstract CargoValidateService getValidateService();
    protected abstract String getProductCode();

    protected abstract void buildInsuranceData(PolicyRequest request, SystemTenantDTO tenant, JcPolicyDTO dto);

    // 公共的创建订单方法
    public Result<PolicyResponseVO> createOrder(@RequestBody OrderRequest request) {
        Result result = new Result<>();
        result.ok();
        try {
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, result);
            if (!result.getSuccess()) {
                return result;
            }

            PolicyRequest policyRequest = apiBaseService.parseRequestData(request.getData(), result);
            if (!result.getSuccess()) {
                return result;
            }

            JcPolicyDTO dto = new JcPolicyDTO();

            buildInsuranceData(policyRequest, tenant, dto);

            processInsuranceFlow(dto, policyRequest, result);

            if (!result.getSuccess()) {
                result.errorMessage(result);
            }
            return result;
        } catch (Exception e) {
            log.error("系统异常: ", e);
            return result.error("系统处理异常，请稍后重试");
        }
    }

    // 保费计算
    public Result calculatePolicy(@RequestBody OrderRequest request) {
        Result result = new Result<>();
        result.ok();
        try {
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, result);
            if (!result.getSuccess()) {
                return result;
            }

            JcPolicyDTO dto = parseInsuranceData(request.getData(), result);
            if (!result.getSuccess()) {
                return result;
            }

            dto.setLogic(OrderConst.PREMIUM_CALCULATION);
            apiBaseService.buildBaseInsuranceData(tenant, dto);

            JcPolicyDTO validDTO = validateBusinessEntity(dto, result);
            if (validDTO == null) {
                return result;
            }

            calculateInsuranceFee(dto, result);
            if (!result.getSuccess()) {
                return result;
            }

            result.ok(apiBaseService.buildResponseVO(dto));
            return result;
        } catch (Exception e) {
            log.error("系统异常: ", e);
            return result.error("系统处理异常，请稍后重试");
        }
    }

    // 创建保单
    public Result createPolicy(@RequestBody OrderRequest request) {
        Result result = new Result<>();
        result.ok();
        try {
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, result);
            if (!result.getSuccess()) {
                result.setContent(request);
                return result;
            }

            JcPolicyDTO dto = parseInsuranceData(request.getData(), result);
            if (!result.getSuccess()) {
                result.setContent(request);
                return result;
            }
            if(!getProductCode().equalsIgnoreCase(dto.getProductCode())){
                log.warn("传入的产品代码与接口不符");
                result.error(ErrorCode.INTERFACE_ERR_CODE, "传入的产品代码与接口不符");
                return result;
            }

            apiBaseService.buildBaseInsuranceData(tenant, dto);


            processInsuranceFlow(dto, null, result);

            if (!result.getSuccess()) {
                result.errorMessage(result);
                result.setContent(JSONUtil.toBean(request.getData(), PolicyVO.class));
            }
            return result;
        } catch (Exception e) {
            log.error("系统异常: ", e);
            return result.error("系统处理异常，请稍后重试");
        }
    }

    // 更新保单
    public Result updatePolicy(@RequestBody OrderRequest request) {
        Result result = new Result<>();
        result.ok();
        try {
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, result);
            if (!result.getSuccess()) {
                result.setContent(request);
                return result;
            }

            JcPolicyDTO dto = parseInsuranceData(request.getData(), result);
            if (!result.getSuccess()) {
                result.setContent(request);
                return result;
            }

            apiBaseService.buildBaseInsuranceData(tenant, dto);

            JcPolicyDTO oldDTO = getInsuranceService().selectByOrderNumberAndSnNo(
                    dto.getOrderNumber(), dto.getSnNo(), dto.getTenantId());

            if (oldDTO == null) {
                return result.error("没有查到有效数据，不能修改！");
            }
            if (OrderConst.STATUS_1.byteValue() != oldDTO.getStatus().byteValue() &&
                    OrderConst.STATUS_10.byteValue() != oldDTO.getStatus().byteValue()) {
                return result.error("当前数据状态，不能修改！");
            }

            dto.setId(oldDTO.getId());
            dto.setUpdateTime(new Date());
            dto.setUpdater(dto.getCreator());
            dto.setCreator(oldDTO.getCreator());
            dto.setCreateTime(oldDTO.getCreateTime());

            processInsuranceFlow(dto, null, result);

            if (!result.getSuccess()) {
                result.errorMessage(result);
                result.setContent(JSONUtil.toBean(request.getData(), PolicyVO.class));
            }
            return result;
        } catch (Exception e) {
            log.error("系统异常: ", e);
            return result.error("系统处理异常，请稍后重试");
        }
    }

    // 查询保单
    public Result<List<PolicyVO>> queryPolicy(@RequestBody OrderRequest request) {
        Result<List<PolicyVO>> result = new Result<>();
        try {
            Result validationResult = new Result();
            validationResult.ok();
            SystemTenantDTO tenant = apiBaseService.validateBaseInfo(request, validationResult);
            if (!validationResult.getSuccess()) {
                validationResult.setContent(request);
                return validationResult;
            }

            List<String> snNoList = parseSnNos(request.getData());
            if (CollectionUtils.isEmpty(snNoList)) {
                return result.ok(Collections.emptyList());
            }
            if (snNoList.size() > 500) {
                return result.error("查询数据比较多，请拆分多次请求");
            }

            List<JcPolicyDTO> dtoList = getInsuranceService().selectList(snNoList, tenant.getId());
            List<PolicyVO> voList = convertToPolicyVoList(dtoList);
            return result.ok(voList);
        } catch (JsonProcessingException e) {
            log.error("JSON解析失败 data:{}", request.getData(), e);
            return result.error("请求数据格式错误");
        } catch (Exception e) {
            log.error("系统异常 request:{}", request, e);
            return result.error("系统处理异常，请稍后重试");
        }
    }

    // 核心业务流程处理
    protected void processInsuranceFlow(JcPolicyDTO dto, PolicyRequest policyRequest, Result result) {
        Result validateResult = getValidateService().validateRequest(policyRequest, dto);
        if (!validateResult.getSuccess()) {
            result.error().setContent(validateResult.getContent());
            result.setCode(ErrorCode.VALIDATION_FAILED);
            return;
        }

        JcPolicyDTO validDTO = validateBusinessEntity((JcPolicyDTO) validateResult.getContent(), result);
        if (validDTO == null) {
            return;
        }

        calculateAndSaveInsurance(validDTO, policyRequest, result);
    }

    // 业务实体验证
    protected JcPolicyDTO validateBusinessEntity(JcPolicyDTO dto, Result result) {
        Result validationResult = getValidateService().validateDTO(dto);
        if (!validationResult.getSuccess()) {
            result.error().setContent(validationResult.getContent());
            result.setCode(ErrorCode.VALIDATION_FAILED);
            return null;
        }
        return (JcPolicyDTO) validationResult.getContent();
    }

    // 计算并保存保险数据
    protected void calculateAndSaveInsurance(JcPolicyDTO dto, PolicyRequest request, Result result) {
        calculateInsuranceFee(dto, result);
        if (!result.getSuccess()) {
            return;
        }

        checkDuplicateOrder(dto, result);
        if (!result.getSuccess()) {
            return;
        }

        persistInsuranceData(dto, request, result);
    }

    // 费用计算流程
    protected void calculateInsuranceFee(JcPolicyDTO dto, Result<?> result) {
        cargoFeeCalculateService.calculateSumInsured(dto);
        Result feeResult = cargoFeeCalculateService.calculatePremium(dto);
        if (!feeResult.getSuccess()) {
            result.error(feeResult.getMessage());
            result.setCode(feeResult.getCode());
        }
    }


    // 重复订单检查
    protected void checkDuplicateOrder(JcPolicyDTO dto, Result<?> result) {
        // 检查订单号是否为空，为空则不进行重复检查
        if (StrUtil.isBlank(dto.getOrderNumber())) {
            return;
        }
        dto.setOrderNumber(dto.getOrderNumber().trim());
        // 查询跨境大货和跨境传统保险服务中的相同订单号保单
        JcPolicyDTO crossExisting = this.insuranceCrossService.selectByOrderNumber(dto.getOrderNumber(), dto.getTenantId());
        JcPolicyDTO traditionalExisting = this.insuranceTraditionalService.selectByOrderNumber(dto.getOrderNumber(), dto.getTenantId());

        // 创建列表存储查询到的保单
        List<JcPolicyDTO> existingPolicies = new ArrayList<>();

        if (crossExisting != null) {
            crossExisting.setProductCode(OrderConst.PRODUCT_CODE_2);
            existingPolicies.add(crossExisting);
        }
        if (traditionalExisting != null) {
            traditionalExisting.setProductCode(OrderConst.PRODUCT_CODE_1);
            existingPolicies.add(traditionalExisting);
        }
        // 如果没有找到现有保单，直接返回
        if (existingPolicies.isEmpty()) {
            return;
        }
        // 如果找到多个保单，直接判定为重复
        if (existingPolicies.size() > 1) {
            result.error("已有相同的原单号数据，请勿重复投保");
            result.setCode(ErrorCode.DUPLICATE_APPLICATION);
            return;
        }
        // 处理只有一个现有保单的情况
        JcPolicyDTO existing = existingPolicies.get(0);
        Boolean isExist = false;
        if (!dto.getProductCode().equalsIgnoreCase(existing.getProductCode())) {
            isExist = true;
        } else {
            if (dto.getId() == null) {
                isExist = true;
            } else if (dto.getId().intValue() != existing.getId().intValue()) {
                isExist = true;
            }
        }
        if (isExist) {
            result.error("已有相同的原单号数据，请勿重复投保");
            result.setCode(ErrorCode.DUPLICATE_APPLICATION);
            log.warn("{},存在相同的原单号：{}", OrderConst.PRODUCT_CODE_2.equalsIgnoreCase(existing.getProductCode()) ? "跨境险" : "传统险", dto.getOrderNumber());
        }
    }


    // 数据持久化处理
    protected void persistInsuranceData(JcPolicyDTO dto, PolicyRequest request, Result result) {
        try {
            if (dto.getId() == null) {
                getInsuranceService().insertPolicy(dto);
                if (dto.getId() == null) {
                    result.setCode(ErrorCode.SYS_ERR_CODE);
                    result.error("投保数据保存失败");
                    return;
                }
            } else {
                getInsuranceService().updatePolicy(dto);
            }

            if (request != null) {
                result.ok(apiBaseService.buildResponseVO(request, dto));
            } else {
                result.ok(apiBaseService.buildResponseVO(dto));
            }
        } catch (DataAccessException e) {
            log.error("数据库操作失败: {}", dto.getOrderNumber(), e);
            result.error("投保数据保存异常");
            result.setCode(ErrorCode.SYS_ERR_CODE);
        }
    }

    // 解析保单数据
    protected JcPolicyDTO parseInsuranceData(String jsonData, Result result) {
        try {
            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return objectMapper.readValue(jsonData, new TypeReference<JcPolicyDTO>() {
            });
        } catch (JsonProcessingException e) {
            log.error("请求数据解析失败: {}", jsonData, e);
            result.error("数据格式错误");
            return null;
        }
    }

    // 解析snNos参数
    protected List<String> parseSnNos(String data) throws JsonProcessingException {
        if (StrUtil.isEmpty(data)) return Collections.emptyList();

        Map<String, String> map = objectMapper.readValue(data, new TypeReference<Map<String, String>>() {
        });
        String snNos = map.get("snNos");
        if (StrUtil.isEmpty(snNos)) return Collections.emptyList();

        return Arrays.stream(snNos.split(","))
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toList());
    }

    // 转换DTO列表为VO列表
    protected List<PolicyVO> convertToPolicyVoList(List<JcPolicyDTO> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) return Collections.emptyList();

        return dtoList.stream().map(dto -> {
            PolicyVO vo = new PolicyVO();
            BeanUtils.copyProperties(dto, vo);

            PolicyResponse response = new PolicyResponse();
            BeanUtils.copyProperties(dto, response);
            vo.setResponse(response);

            return vo;
        }).collect(Collectors.toList());
    }
}